package bapi

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
	"io"
	"net/http"
	"time"
)

const (
	APP_KEY    = "xyy"
	APP_SECRET = "go-programming-tour-book"
)

type AccessToken struct {
	Token string `json:"token"`
}

// 所有 API 请求都需要带上的 AccessToken 的获取方法
func (a *API) getAccessToken(ctx context.Context) (string, error) {
	url := fmt.Sprintf(
		"%s",
		"auth",
	)
	body, err := a.httpPost(ctx, url)
	if err != nil {
		return "", err
	}

	var accessToken AccessToken
	_ = json.Unmarshal(body, &accessToken)
	return accessToken.Token, nil
}

// API SDK 统一的 HTTP GET 的请求方法
func (a *API) httpGet(ctx context.Context, path string) ([]byte, error) {
	url := fmt.Sprintf("%s/%s", a.URL, path)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	span, newCtx := opentracing.StartSpanFromContext(
		ctx, "HTTP GET: "+a.URL,
		opentracing.Tag{Key: string(ext.Component), Value: "HTTP"},
	)
	span.SetTag("url", url)
	_ = opentracing.GlobalTracer().Inject(
		span.Context(),
		opentracing.HTTPHeaders,
		opentracing.HTTPHeadersCarrier(req.Header),
	)
	req = req.WithContext(newCtx)
	client := http.Client{Timeout: time.Second * 60}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	defer span.Finish()

	//读取消息主体，在实际封装中可以将其抽离
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return body, nil
	//resp, err := http.Get(fmt.Sprintf("%s/%s", a.URL, path))
	//if err != nil {
	//	return nil, err
	//}
	//defer resp.Body.Close()
	//body, _ := io.ReadAll(resp.Body)
	//return body, nil
}

// API SDK 统一的 HTTP POST 的请求方法
func (a *API) httpPost(ctx context.Context, path string) ([]byte, error) {
	requestBody := []byte(`{"app_key":"xyy","app_secret":"go-programming-tour-book"}`)
	req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/%s", a.URL, path), bytes.NewBuffer(requestBody))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	return body, nil
}

/*
从 blog_service 项目中获取 AccessToken，完成各类数据源的接口编写
*/

type API struct {
	URL string
}

func NewAPI(url string) *API {
	return &API{URL: url}
}

func (a *API) GetTagList(ctx context.Context, name string) ([]byte, error) {
	token, err := a.getAccessToken(ctx)

	//token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBfa2V5IjoiMjA2YzkwNzc4NmYxYjQ0MmJlYjM1YjM2NTQ2ZWZkMDAiLCJhcHBfc2VjcmV0IjoiN2M5NzI2NjMxNzBkNmJjMTg0ODRkMDViYzk4NzIyZjQiLCJleHAiOjE3MDEyNjY2MzgsImlzcyI6ImJsb2dfc2VydmljZSJ9.VgpsZXmX-FeloXq3LqM38EVMBD3BLY5sL1lE9vHENj0"
	if err != nil {
		return nil, err
	}

	body, err := a.httpGet(ctx, fmt.Sprintf(
		"%s?token=%s&name=%s",
		"api/v1/tags",
		token,
		name,
	))
	if err != nil {
		return nil, err
	}

	return body, nil
}
